/**
 *****************************************************************************
 * @file
 * @brief
 * @author taoye
 * @version V0.0.1
 * @date 2021/08/24
 ****************************************************************************
 */
 
  /* Includes ------------------------------------------------------------------*/
#include "drv_f4_spi.h"

/* Private defines -----------------------------------------------------------*/
#define     SOFT_SET_BIT(x, y)          (x |=  (1 << y))
#define     SOFT_CLEAR_BIT(x, y)        (x &= ~(1 << y))

#define     SOFT_READ_BIT(x, y)         ((x >> y) & 1)
#define     SOFT_WRITE_BIT(x, y, flag)  (flag ? SOFT_SET_BIT(x, y) : SOFT_CLEAR_BIT(x, y))

#define     SOFTSPI_SCK_SET(x)          {(this->private.sck.Write   ) (&this->private.sck,     x); }
#define     SOFTSPI_MISO_READ           ((this->private.miso.Read   ) (&this->private.miso))

#define     SOFTSPI_MOSI_SET(x)                                     \
{                                                                   \
    if(this->PIN_MOSI != NULL){                                     \
        (this->private.mosi.Write  ) (&this->private.mosi,    x);   \
    }                                                               \
}                                                                   \

#define     SOFTSPI_CS_SET(x)                                       \
{                                                                   \
    if(this->PIN_CS != NULL){                                       \
        (this->private.cs.Write    ) (&this->private.cs,      x);   \
    }                                                               \
                                                                    \
}                                                                   \

/* Private Struct  -----------------------------------------------------------*/


/* Private enum    -----------------------------------------------------------*/


/* Private Variable  ---------------------------------------------------------*/

/***********************************************************************************
 * @brief
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
int SoftSpi_Init( drv_spi_t * this )
{
    // 私有属性赋值
    this->private.cs.PIN   = this->PIN_CS;
    this->private.sck.PIN  = this->PIN_SCK;
    this->private.miso.PIN = this->PIN_MISO;
    this->private.mosi.PIN = this->PIN_MOSI;

    this->private.cs.MODE      = OUTPUT_UP;
    this->private.sck.MODE     = OUTPUT_UP;
    this->private.miso.MODE    = INPUT_UP;
    this->private.mosi.MODE    = OUTPUT_UP;

    if(this->CS_EN  != SPI_CS_NULL && this->CS_EN  == SPI_CS_EN_L){
        this->private.cs.INIT_LEVEL  = HIGHT_LEVEL;
    }
    else{
        this->private.cs.INIT_LEVEL  = LOW_LEVEL;
    }
    if(this->CPOL == SPI_CPOL_H){
        this->private.sck.INIT_LEVEL  = HIGHT_LEVEL;
    }
    else{
        this->private.sck.INIT_LEVEL  = LOW_LEVEL;
    }
    this->private.mosi.INIT_LEVEL  = LOW_LEVEL;


    // 私有属性初始化
    if(Drv_Gpio_Init(&this->private.cs) < 0){
        return -1;
    }
    if(Drv_Gpio_Init(&this->private.sck) < 0){
        return -1;
    }
    if(Drv_Gpio_Init(&this->private.miso) < 0){
        return -1;
    }
    if(Drv_Gpio_Init(&this->private.mosi) < 0){
        return -1;
    }

    return 0;
}

/***********************************************************************************
 * @brief 		ReadWrite
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static void SoftSpi_ReadWrite(drv_spi_t *this, void *write, void *read, uint32_t len)
{ 
    uint8_t mask;
    uint8_t p_add = this->TRANS / 8;
    uint32_t write_buf,read_buf;
    
    #if defined NEW_HARDWARE_WITH_ERROR_SPI
    if(this->CS_EN != SPI_CS_NULL){
        SOFTSPI_CS_SET(this->CS_EN  == SPI_CS_EN_L);
        SoftDelay_us(this->CS_DELAY_US);   
    }
    #else
    if(this->CS_EN != SPI_CS_NULL){
    SOFTSPI_CS_SET(this->CS_EN  == SPI_CS_EN_H);
    SoftDelay_us(this->CS_DELAY_US);   
    }
    #endif
    
    while(len > 0){
        
             if(this->TRANS == SPI_TRANS_BYTE)          write_buf = *(uint8_t *) write;
        else if(this->TRANS == SPI_TRANS_HALFWORD)      write_buf = *(uint16_t *)write;
        else if(this->TRANS == SPI_TRANS_THREEBYTE || 
                this->TRANS == SPI_TRANS_WORD)          write_buf = *(uint32_t *)write;
        else                                            return;
        read_buf = 0;
        
        (this->ORDER == SPI_MSB) ? (mask = this->TRANS - 1) : (mask = 0);
        
        if(this->CPHA == SPI_CPHA_1){
            
            for (uint8_t i = 0; i < this->TRANS; i++)
            {
                // MOSI
                SOFTSPI_MOSI_SET(SOFT_READ_BIT(write_buf, mask));
                // CLK1
                SOFTSPI_SCK_SET(this->CPOL == SPI_CPOL_L);
                // MISO
                if(this->PIN_MISO != NULL){
                    SOFT_WRITE_BIT(read_buf, mask, SOFTSPI_MISO_READ);
                }             
                // CLK2
                SOFTSPI_SCK_SET(this->CPOL == SPI_CPOL_H);
                // mask change
                (this->ORDER == SPI_MSB) ? (mask --) : (mask ++);
            }        
        }
        else{
        
            for (uint8_t i = 0; i < this->TRANS; i++)
            {
                // CLK1
                SOFTSPI_SCK_SET(this->CPOL == SPI_CPOL_L);    
                // MOSI
                SOFTSPI_MOSI_SET(SOFT_READ_BIT(write_buf, mask)); 
                // CLK2
                SOFTSPI_SCK_SET(this->CPOL == SPI_CPOL_H);
                // MISO
                if(this->PIN_MISO != NULL){
                    SOFT_WRITE_BIT(read_buf, mask, SOFTSPI_MISO_READ);  
                }           
                // mask change
                (this->ORDER == SPI_MSB) ? (mask --) : (mask ++);
            } 
        }  
             if(this->TRANS == SPI_TRANS_BYTE)          *(uint8_t *) read   = (uint8_t)read_buf;
        else if(this->TRANS == SPI_TRANS_HALFWORD)      *(uint16_t *)read   = (uint16_t)read_buf;
        else if(this->TRANS == SPI_TRANS_THREEBYTE|| 
                this->TRANS == SPI_TRANS_WORD)          *(uint32_t *)read   = (uint32_t)read_buf;
        else                                            return;
        
        write = (uint8_t *)write + p_add;
        read  = (uint8_t *)read  + p_add;
        len --;
    }
    
    #if defined NEW_HARDWARE_WITH_ERROR_SPI
    if(this->CS_EN != SPI_CS_NULL){
        SoftDelay_us(this->CS_DELAY_US);
        SOFTSPI_CS_SET(this->CS_EN  == SPI_CS_EN_H);
    }
    #else
    if(this->CS_EN != SPI_CS_NULL){
    SoftDelay_us(this->CS_DELAY_US);
    SOFTSPI_CS_SET(this->CS_EN  == SPI_CS_EN_L);
    }
    #endif
}

/***********************************************************************************
 * @brief
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
int HardSpi_Init(drv_spi_t *this)
{
    SPI_InitTypeDef     SPI_InitStructure;
    uint8_t             afconfig;

    if(this->private.SPIx == SPI1){
        afconfig = GPIO_AF_SPI1;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    }
    else if(this->private.SPIx == SPI2){
        afconfig = GPIO_AF_SPI2;
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
    }
    else if(this->private.SPIx == SPI3){
        afconfig = GPIO_AF_SPI3;
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
    }
    else if(this->private.SPIx == SPI4){
        afconfig = GPIO_AF_SPI4;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI4, ENABLE);
    }
    else if(this->private.SPIx == SPI5){
        afconfig = GPIO_AF_SPI5;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI5, ENABLE);
    }
    else if(this->private.SPIx == SPI6){
        afconfig = GPIO_AF_SPI6;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI6, ENABLE);
    }

    // CS开启硬件使能
    if(this->CS_EN != SPI_CS_NULL){
        if(Common_Gpio_AFConfig(this->PIN_CS,   afconfig, GPIO_PuPd_UP) < 0){
            return -1;
        }
        SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;
    }
    else{
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    }
    // MOSI
    if(Common_Gpio_AFConfig(this->PIN_MOSI, afconfig, GPIO_PuPd_UP) < 0){
        return -1;
    }
    // MISO
    if(Common_Gpio_AFConfig(this->PIN_MISO, afconfig, GPIO_PuPd_NOPULL) < 0){
        return -1;
    }
    // CLK
    if(Common_Gpio_AFConfig(this->PIN_SCK, afconfig, GPIO_PuPd_UP) < 0){
        return -1;
    }

    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

    if(this->TRANS == SPI_TRANS_BYTE){
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    }
    else if(this->TRANS == SPI_TRANS_HALFWORD){
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
    }

    if(this->CPHA == SPI_CPHA_1){
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    }
    else if(this->CPHA == SPI_CPHA_2){
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
    }

    if(this->CPOL == SPI_CPOL_H){
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
    }
    else if(this->CPOL == SPI_CPOL_L){
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    }

    if(this->SPEED == SPI_SPEED_HIGH){
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
    }
    else if(this->SPEED == SPI_SPEED_MEDIUM){
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
    }
    else if(this->SPEED == SPI_SPEED_SLOW){
        //SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
		SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
		
    }   

    if(this->ORDER == SPI_MSB){
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    }
    else if(this->ORDER == SPI_LSB){
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
    }

    SPI_InitStructure.SPI_CRCPolynomial = 7;

    SPI_Cmd(this->private.SPIx, DISABLE);
    SPI_Init(this->private.SPIx, &SPI_InitStructure);

		
	
    if(this->CS_EN != SPI_CS_NULL){
        SPI_SSOutputCmd(this->private.SPIx, ENABLE);
    }

    SPI_Cmd(this->private.SPIx, ENABLE);

    return 0;
}

/***********************************************************************************
 * @brief 		ReadWrite
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static void HardSpi_ReadWrite(drv_spi_t *this, void *write, void *read, uint32_t len)
{
    uint32_t i;
    uint8_t p_add = this->TRANS / 8;
    uint32_t write_buf,read_buf;
	uint32_t time_count = 0;
	
    for(i=0; i<len; i++){

             if(this->TRANS == SPI_TRANS_BYTE)        write_buf = *(uint8_t *) write;
        else if(this->TRANS == SPI_TRANS_HALFWORD)    write_buf = *(uint16_t *)write;

        // 等待发送区空  
        while (SPI_I2S_GetFlagStatus(this->private.SPIx, SPI_I2S_FLAG_TXE) == RESET);
        SPI_I2S_SendData(this->private.SPIx, write_buf);

        //等待接收完一个byte
        while (SPI_I2S_GetFlagStatus(this->private.SPIx, SPI_I2S_FLAG_RXNE) == RESET)
		{
			
			time_count++;
			if(time_count > 30000)
			{
				Ashell_print("spi recv fail\r\n");
			}
		
		}
        read_buf = SPI_I2S_ReceiveData(this->private.SPIx);

             if(this->TRANS == SPI_TRANS_BYTE)        *(uint8_t *) read   = read_buf;
        else if(this->TRANS == SPI_TRANS_HALFWORD)    *(uint16_t *)read   = read_buf;

        write = (uint8_t *)write + p_add;
        read  = (uint8_t *)read  + p_add;
    }
}

/***********************************************************************************
 * @brief
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
int Drv_Spi_Init( drv_spi_t * this )
{
    if(strcmp(this->DRV, "SOFTSPI") == 0){
        if(SoftSpi_Init(this) < 0){
            return -1;
        }
        // 公共方法赋值
        this->ReadWrite = SoftSpi_ReadWrite;        
    }
    else{
        uint8_t nlen = strlen(this->DRV);
        if(nlen != 4){
            return -1;
        }
        uint8_t index = this->DRV[nlen - 1] - '0';
        switch(index)
        {
            case 1:
                this->private.SPIx = SPI1;
            break;
            case 2:
                this->private.SPIx = SPI2;
            break;
            case 3:
                this->private.SPIx = SPI3;
            break;
            case 4:
                this->private.SPIx = SPI4;
            break;
            case 5:
                this->private.SPIx = SPI5;
            break;
            case 6:
                this->private.SPIx = SPI6;
            break;
            default:
                return  -1;
        }

        if(HardSpi_Init(this) < 0){
            return -1;
        }
        // 公共方法赋值
        this->ReadWrite = HardSpi_ReadWrite;
    }

    return 0;
}


